package BLC

import (
	"fmt"
	"github.com/boltdb/bolt"
	"log"
)

//数据库的名字
const dbFile="blockchain.db"

//相当于表的名字
const blockBucket="blocks"

type BlockChain struct{
	Tip []byte  //区块链里面最后一个区块的hash值
	DB *bolt.DB
}

//创建一个带有创世纪区块的数组
func NewBlockChain()*BlockChain{
	var tip []byte
	var genist *Block

	//1.尝试打开或者是创建数据库
	db,err:=bolt.Open(dbFile,0600,nil)
	if err!=nil{
		panic(err)
	}

	//拿到创世区块
	//genist=NewGenisBlock()
	//SeriGenist:=genist.SerilizeBlock()

	//2.更新数据库
	//下面的代码是创建或者更新表
	err=db.Update(func (tx *bolt.Tx)error{
		//判断表是否存在
		b:=tx.Bucket([]byte(blockBucket))

		if b==nil{ //如果表不存在

			genist=NewGenisBlock()
			SeriGenist:=genist.SerilizeBlock()

			fmt.Println("这张表不存在，正在创建一张新的表......")

			//创建表
			b,err:=tx.CreateBucket([]byte(blockBucket))
			if err!=nil{
				log.Panic(err)
			}

			//添加数据到表
			err=b.Put(genist.Hash,SeriGenist)
			if err!=nil{
				log.Panic(err)
			}

			//"l"保存的是最后一个区块的hash值
			err=b.Put([]byte("l"),genist.Hash)
			if err!=nil{
				log.Panic(err)
			}

			tip=genist.Hash
		}else{
			tip=b.Get([]byte("l"))
		}

		return nil
	})


	if err!=nil{
		panic(err)
	}

	return &BlockChain{tip,db}
}


func (bc *BlockChain)AddBlock(data string){
		newBlock:=NewBlock(data,bc.Tip)

		err:=bc.DB.Update(func (t *bolt.Tx)error{

			b:=t.Bucket([]byte(blockBucket))

			err:=b.Put(newBlock.Hash,newBlock.SerilizeBlock())
			if err!=nil{
				panic(err)
			}

			err=b.Put([]byte("l"),newBlock.Hash)
			if err!=nil{
				panic(err)
			}

			bc.Tip=newBlock.Hash


			return nil
		})

		if err!=nil{
			panic(err)
		}
	}

//遍历整个区块链
func (bc *BlockChain)ViewBlockChain(){
	err:=bc.DB.View(func (tx *bolt.Tx)error{
		b:=tx.Bucket([]byte(blockBucket))
		theBlock:=b.Get(bc.Tip)
		i:=1
		for  theBlock!=nil{
			block:=UnSerilizeBlock(theBlock)
			fmt.Println("倒数第",i,"个区块的内容是:")
			block.Print()
			i+=1
			theBlock=b.Get(block.PreviewHash)
		}

		return nil
	})
	if err!=nil{
		panic(err)
	}
}